Skip to content

Changes for Ziggurat 0.2.0#3

Open
puddly wants to merge 34 commits into
devfrom
puddly/ziggurat-0.2
Open

Changes for Ziggurat 0.2.0#3
puddly wants to merge 34 commits into
devfrom
puddly/ziggurat-0.2

Conversation

@puddly

@puddly puddly commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

This is a (WIP) aggregate PR for the changes required to support the upcoming Ziggurat 0.2.0 release. Notable features:

  • New send API that splits enqueuing, confirmation, and (optionally) APS ACK into three separate callbacks.
  • Support the zigpy packet capture API
  • Allow directly connecting to a serial port, for ESP32-C6 support. This is the WebSocket but line-based. It is provisional and will change when Ziggurat 1.0.0 is released, likely turning into a normal binary protocol.

@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (635c76a) to head (b0ff49f).

Additional details and impacted files
@@            Coverage Diff             @@
##               dev        #3    +/-   ##
==========================================
  Coverage   100.00%   100.00%            
==========================================
  Files            2         5     +3     
  Lines          644      1412   +768     
==========================================
+ Hits           644      1412   +768     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@puddly
puddly marked this pull request as ready for review July 10, 2026 01:53
tube0013 added a commit to tube0013/addons that referenced this pull request Jul 21, 2026
The wire-protocol mismatch that motivated tcp-adaptor-support-legacy-protocol
is being fixed on the zigpy-ziggurat side instead (zigpy/zigpy-ziggurat#3),
so this points back at the real PR branch. Pins to a commit via --rev rather
than tracking --branch, since Docker's layer cache only invalidates when an
ARG value actually changes, and a moving branch name would otherwise risk
silently reusing a stale build across rebuilds.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@burmistrzak

Copy link
Copy Markdown

@puddly Do you think the protocol is already stable enough to make a zigbee-herdsman port worthwhile or will there be additional breaking changes ahead?
I'm asking because we'll need some extra lead time to prepare the necessary plumbing on the ZH end. 😅

@puddly

puddly commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

I, uh, have another PR incoming that modifies the wire format yet again 😅. It should be the final breaking change for a while, all future changes should be additive and backwards-compatible via reserved bitmap flags. I'm hoping to get everything finalized and released before Wednesday since that is the Home Assistant Core beta cutoff.

Copilot AI review requested due to automatic review settings July 25, 2026 18:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aggregates the host-side changes needed for the upcoming Ziggurat 0.2.0 release by introducing a new binary control protocol, adding new transport options (binary WebSocket + Spinel tunnel), and updating the zigpy radio integration to use the new request/confirm callback model.

Changes:

  • Added generated binary wire types and a higher-level binary protocol API (requests/responses/notifications, encoding helpers, errors).
  • Implemented transport layer supporting binary WebSocket, legacy JSON WebSocket transcoding, and serial (Spinel tunnel) connectivity.
  • Updated the zigpy ControllerApplication integration for the new send-confirm model, packet capture support, tunables, and counter restore behavior; expanded tests accordingly.

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
zigpy_ziggurat/zigbee/wire.py Adds generated binary wire structs/enums used by the new protocol layer.
zigpy_ziggurat/zigbee/transport.py Introduces WebSocket + Spinel transports and legacy JSON transcoding.
zigpy_ziggurat/zigbee/protocol.py Defines the binary protocol request/response/notification API and helpers.
zigpy_ziggurat/zigbee/legacy.py Extends/adjusts legacy JSON models to support added fields and packet capture.
zigpy_ziggurat/zigbee/application.py Migrates zigpy radio integration to the new API, send/confirm flow, and packet capture.
zigpy_ziggurat/zigbee/api.py Implements a transport-agnostic request/stream/confirm API over binary frames.
zigpy_ziggurat/config.py Adds Ziggurat-specific config schema (tunables).
pyproject.toml Adds aiospinel dependency for Spinel tunnel support.
uv.lock Locks aiospinel and updates dependency metadata.
tests/test_transport.py Adds transport probe/transport behavior coverage (binary/legacy/spinel).
tests/test_protocol.py Adds tests for protocol convenience accessors and round-trips.
tests/test_application.py Updates application tests for new counters, send behavior, and packet capture.
tests/test_api.py Reworks API tests around a fake binary transport and confirms/cancel behavior.
tests/common.py Extends synthetic servers to include binary WebSocket and Spinel RCP fixtures/helpers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread zigpy_ziggurat/config.py
Comment on lines +15 to +17
vol.Optional(CONF_TUNABLES, default={}): vol.Schema(
{vol.Optional(str): int}
)
Comment on lines +77 to +81
def _connection_lost(self, exc: BaseException | None) -> None:
for pending in self._pending.values():
if not pending.response.done():
pending.response.set_exception(ConnectionError("Connection lost"))
self._pending.clear()
Comment on lines +179 to +184
async def _probe_websocket(url: str, on_frame: OnFrame, on_lost: OnLost) -> Transport:
"""Pick the transport from the server's opening hello: binary frame or JSON text."""
session, websocket = await _open_websocket(url)
async with asyncio.timeout(HANDSHAKE_TIMEOUT):
hello = await websocket.receive()

Comment on lines 105 to 108
def __init__(self, config: dict[str, Any]) -> None:
super().__init__(config)
self._api: ZigguratApi | None = None

Comment on lines +540 to +548
# The backup carries no capability, so device type is Unknown (restored as a
# sleepy end device); children without a known NWK address can't be loaded.
entries = [
p.ChildEntry(
ieee=ieee,
nwk=network_info.nwk_addresses[ieee],
rx_on_when_idle=t.uint1_t(1),
device_type=p.ChildDeviceType.UNKNOWN,
reserved=t.uint5_t(0),
Comment on lines +213 to +218
asdu: bytes,
route_control: RouteControl = RouteControl.STACK_DECIDES,
next_hop: t.NWK | None = None,
relays: list[t.NWK] | None = None,
) -> SendUnicast:
return cls(
@burmistrzak

Copy link
Copy Markdown

I, uh, have another PR incoming that modifies the wire format yet again 😅.

Hehe, I figured. That's why I asked. ☺️

It should be the final breaking change for a while, all future changes should be additive and backwards-compatible via reserved bitmap flags. I'm hoping to get everything finalized and released before Wednesday since that is the Home Assistant Core beta cutoff.

There's a small chance we'll be able to ship a beta ziggurat adapter with the next regular Z2M release on Saturday. 🤞🤞

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants